#ifndef CLUSNET_NET_TCPCLIENT_H
#define CLUSNET_NET_TCPCLIENT_H

#include <boost/asio.hpp>
#include "Callbacks.h"
#include "TcpConnection.h"

namespace clusnet
{
namespace net
{

class TcpClient final : public std::enable_shared_from_this<TcpClient>
{
    enum class TcpClientState : uint8_t
    {
        CONNECTING = 0,
        CONNECTED = 1,
        UNCONNECTED = 2,
        CLOSED = 3
    };

    public:
        TcpClient(boost::asio::io_context& io_context, const char* host, const char* port, const boost::asio::ip::tcp::resolver::protocol_type& proto = boost::asio::ip::tcp::v4(), bool reconn = true, bool nodelay = true, bool keepAlive = false);
        ~TcpClient();
        TcpClient(const TcpClient&) = delete;
        TcpClient& operator= (const TcpClient&) = delete;

    public:
        void safeStartConnect();
        void safeAsyncWrite(const TcpDataPacketPtr& data);
        void safeClose();

    public:
        void setNewConnectionCallback(const TcpNewConnectionCallback& cb) { newConnCallback_ = cb; }
        void setWriteCompleteCallback(const TcpWriteCompleteCallback& cb) { writeCallback_ = cb; }
        void setMessageCallback(const TcpMessageCallback& cb) { messageCallback_ = cb; }
        void setCloseCallback(const TcpCloseCallback& cb) { closeCallback_ = cb; }

    private:
        void handleConnect(const boost::system::error_code&, const boost::asio::ip::tcp::endpoint& endpoint);
        void handleClose(TcpConnectionPtr&);
        void handleMessage(TcpConnectionPtr&, TcpUniqDataPacketPtr&&);
        void handleWriteComplete(TcpConnectionPtr&, const TcpDataPacketPtr&);
        void safeReconnect();

    private:
        boost::asio::ip::tcp::resolver::results_type getEndPoints() const
        {
            boost::asio::ip::tcp::resolver resolver(io_);
            return resolver.resolve(proto_, host_, port_);
        }

    private:
        boost::asio::io_context&            io_;
        boost::asio::io_context::strand     strand_;
        TcpConnectionPtr                    conn_;
        bool                                reconn_;
        boost::asio::steady_timer           reconnTimer_;
        bool                                nodelay_;
        bool                                keepAlive_;
        const std::string                   host_;
        const std::string                   port_;
        const boost::asio::ip::tcp::resolver::protocol_type     proto_;
        TcpNewConnectionCallback               newConnCallback_;
        TcpCloseCallback                       closeCallback_;
        TcpWriteCompleteCallback               writeCallback_;
        TcpMessageCallback                     messageCallback_;

        TcpClientState                      state_;
};
}
}

#endif 
